/*
 * This file is part of ELCube.
 *
 * ELCube is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ELCube is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ELCube.  If not, see <https://www.gnu.org/licenses/>.
 */
package cn.nkpro.elcube.docengine.model.es;

import cn.nkpro.elcube.data.elasticearch.AbstractESModel;
import cn.nkpro.elcube.data.elasticearch.ESAnalyzerType;
import cn.nkpro.elcube.data.elasticearch.ESFieldType;
import cn.nkpro.elcube.data.elasticearch.annotation.ESDynamicTemplate;
import cn.nkpro.elcube.data.elasticearch.annotation.ESField;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Created by bean on 2020/7/6.
 */
@EqualsAndHashCode(callSuper = true)
@Data
public abstract class AbstractBaseES extends AbstractESModel {

    @ESField(type= ESFieldType.Integer)
    protected Integer $ = 1;

    @ESField(type= ESFieldType.Keyword)
    private String classify;

    @ESField(type= ESFieldType.Keyword)
    private String docType;

    @ESField(type= ESFieldType.Keyword)
    private String docTypeDesc;

    @ESField(type= ESFieldType.Keyword)
    private String docNumber;

    @ESField(type= ESFieldType.Keyword)
    private String docState;

    @ESField(type= ESFieldType.Keyword)
    private String docStateDesc;

    @ESField(type= ESFieldType.Integer)
    private Integer docDefVersion;

    @ESField(type= ESFieldType.Date, format = "epoch_second||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd")
    private Long createdTime;

    @ESField(type= ESFieldType.Date, format = "epoch_second||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd")
    private Long updatedTime;

    @ESField(type= ESFieldType.Text,analyzer = ESAnalyzerType.ik_max_word, copyToKeyword = true, original = true)
    private String docName;

    @ESField(type= ESFieldType.Keyword)
    private String preDocId;

    @ESField(type= ESFieldType.Keyword)
    private String[] tags;

    @ESField(type= ESFieldType.Keyword)
    private String partnerId;

    @ESField(type= ESFieldType.Keyword)
    private String processInstanceId;

    @ESField(type= ESFieldType.Text,analyzer = ESAnalyzerType.standard, copyToKeyword = true, original = true)
    private String partnerName;

    @Override
    protected Map<String,Object> toSource(){
        Map<String,Object> map = (JSONObject) JSON.toJSON(this);
        map.put("$",$);
        return map;
    }

    public AbstractBaseES makeDefaults(List<String> keys){
        $ = 0;

        Map<String,String> mappingTypes = new HashMap<>();
        ESDynamicTemplate[] annotations = getClass().getAnnotationsByType(ESDynamicTemplate.class);
        Arrays.stream(annotations).forEach(annotation->
                mappingTypes.put(annotation.match().replaceAll("[*]",".*"),annotation.mappingType().getValue())
        );

        keys.forEach(key-> {
            for(String pattern : mappingTypes.keySet()){
                if(Pattern.matches(pattern,key)){
                    switch (mappingTypes.get(pattern)){
                        case "text":
                        case "completion":
                        case "keyword":
                        case "attachment":
                            addDynamicField(key, StringUtils.EMPTY);
                            break;
                        case "boolean":
                            addDynamicField(key,false);
                            break;
                        case "object":
                        case "nested":
                            addDynamicField(key, new HashMap<>());
                            break;
                        case "ip":
                            addDynamicField(key, "0.0.0.0");
                            break;
                        default:
                            addDynamicField(key,0);
                    }
                    break;
                }
            }
        });

        defaults();
        return this;
    }

    protected abstract void defaults();
}
